package com.zxl.aspect;

import com.zxl.annotations.ExecutorChoose;
import com.zxl.support.ExecutorThreadPool;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Description: 根据datasourceId动态的选择线程池并进行业务的执行
 *
 * @Author: zxl
 *
 * @Date: 2022/9/29
 *
 */
@Aspect
@Component
@Slf4j
public class ExecutorChooseAspect {

    @Resource
    private ExecutorThreadPool executorThreadPool;

    @Pointcut("@annotation(com.zxl.annotations.ExecutorChoose)")
    public void ExecutorChoosePointCut() {
    }

    @Around("ExecutorChoosePointCut()")
    public void around(ProceedingJoinPoint point) {
        try {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = point.getTarget().getClass()
                    .getMethod(signature.getName(), signature.getMethod().getParameterTypes());
            ExecutorChoose executorAsync = method.getAnnotation(ExecutorChoose.class);
            String value = executorAsync.value();
            String type = executorAsync.type();
            ExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression(value);
            EvaluationContext context = new StandardEvaluationContext();
            Object[] args = point.getArgs();
            DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = discoverer.getParameterNames(method);
            for (int i = 0; i < Objects.requireNonNull(parameterNames).length; i++) {
                context.setVariable(parameterNames[i], args[i].toString());
            }
            String valueId = Objects.requireNonNull(expression.getValue(context)).toString();
            ThreadPoolExecutor executor = executorThreadPool.getThreadPoolExecutor(type + "_" + valueId);
            executor.execute(() -> {
                try {
                    point.proceed();
                } catch (Throwable e) {
                    log.error("统计库表数据量失败：" + e.getMessage());
                }
            });
        } catch (NoSuchMethodException e) {
            log.error("统计库表数据量失败：" + e.getMessage());
        }
    }
}